;*****************************************************************************************************
;+
; NAME:
;       IGL_GRAPHIC
;
; PURPOSE:
;
;       This is the second most important object in the Interactive
;       Graphics Library. A "graphic" is a portion of the window where
;       other objects (mostly IGL_BaseRangeObjects like plots, axis,
;       etc.) can be displayed. It is needed to regroup the objects
;       coherently and to interface them with the IGL_Window
;       object. All the objects added to the graphic share the same
;       POSITION array. Each children of the graphic object represent
;       one coordinate system and objects which share the same
;       coordinate system are added as grand-children. 
;
;
; AUTHORS:
;
;        RAPHAEL SADOUN
;        Graduate Student
;        Institut d'Astrophysique de Paris
;        98 bis boulevard Arago
;        75014 PARIS FRANCE
;        E-mail: raphael.sadoun@gmail.com
;
; SUPERCLASSES:
;
;       CATDATAATOM (Catalyst Library)
;
; SYNTAX:
;
;       graphic = Obj_New('IGL_Graphic')
;
;
; CLASS_STRUCTURE:
;
;       class = {IGL_Graphic, $
;            INHERITS CATDATAATOM, $ ; This is a CATDATAATOM object
;            visible:0B $ 
;           }
;
;
; MODIFICATION_HISTORY:
;
;       Written by: Raphael Sadoun, 24 April 2012
;-
;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::ADD
;
; PURPOSE:
;
;       This method overloads the default behaviour of the
;       CatAtom::Add method. It is done to be able to automatically
;       set the position of the added object(s) to the position of this graphic.
;
; SYNTAX:
;
;       self -> Add
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       None.
;
;-
;*****************************************************************************************************
PRO IGL_Graphic::Add, object, _EXTRA=extra

  ;; Here we automatically update the position of the coordinate
  ;; system of the added child object(s) since they must have the same one
  ;; as this graphic.
     
  ;; Make sure we have a valid coordinate system
  IF (obj_isa_valid(self._coords,'CatCoord') EQ 0) THEN return
  
  ;; Get the graphic's current coordinate information
  self._coords -> GetProperty, Position=position
  
  ;; Set the position of the new objects to that of the graphic
  FOR i=0, n_elements(object)-1 DO BEGIN
     
     IF (obj_isa_valid(object[i],'CatDataAtom')) THEN BEGIN
        
        object[i] -> GetProperty, coord_object=coords
        IF (obj_isa_valid(coords,'CatCoord')) THEN coords -> SetProperty, position=position
        
     ENDIF
     
  ENDFOR

  ;; Add the object to the graphic
  self -> CatAtom::Add, object, _extra=extra

  ;; Report completion
  self -> Report, /Completed
  
END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::CONTROLPANEL
;
; PURPOSE:
;
;       This method creates a control panel for the graphic.
;
; SYNTAX:
;
;       self -> ControlPanel, baseObject
;
; ARGUMENTS:
;
;       baseObject:    The object reference of a base widget for this control to
;                      be added to. If not supplied, the control panel will be in a
;                      self contained window.
;
; KEYWORDS:
;
;       _EXTRA:       Any keywords appropriate for the CATCONTROLPANEL::INIT method.
;-
;*****************************************************************************************************
PRO IGL_Graphic::ControlPanel, baseObject, _EXTRA=extraKeywords

   @cat_pro_error_handler

   ;; Create a new control panel
   cp = OBJ_NEW ('CatControlPanel', self, PARENT=baseObject, COLUMN=1, $
      TITLE='IGL_Graphic Control Panel', _EXTRA=extraKeywords, /No_Cancel, /No_Apply, /No_OK)

   IF (NOT OBJ_VALID (cp)) THEN RETURN

   aproperties = Obj_New('PROPERTYSHEETWIDGET', cp, Value=self, Name='IGL_GRAPHIC PROPERTYSHEET', YSize=4)
   aproperties -> SetProperty, Event_Object=self

   ;; Display the control panel if it created its own TLB.
   IF cp -> Created_Own_TLB(tlb) THEN tlb -> Draw, /Center

   ;; Report completion
   self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::DRAW
;
; PURPOSE:
;
;       This method draws the graphic in the current display window.
;
; SYNTAX:
;
;       self -> Draw
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       _EXTRA:    Any keyword accepted by the CATATOM::Draw method.
;
;-
;*****************************************************************************************************
PRO IGL_Graphic::Draw, _Extra=extrakeywords

   @cat_pro_error_handler

   ;; If the selectable object is invisible, then return immediately.
   IF self.visible EQ 0 THEN RETURN

   ;; Apply the coordinate system.
   self -> ApplyCoords

   ;; Draw the objects contained in the graphic
   self -> CatAtom::Draw, _Extra=extrakeywords

   ;; Report completion
   self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::EVENTHANDLER
;
; PURPOSE:
;
;       This method is an event handler for the Control Panel.
;
; SYNTAX:
;
;       Called automatically by the event handling system
;
; ARGUMENTS:
;
;       event:  The event structure.
;
; KEYWORDS:
;
;       None.
;-
;*****************************************************************************************************
PRO IGL_Graphic::EventHandler, event

   @cat_pro_error_handler

   ;; Get the name of the widget generating the event. Branch on this.
   event.ID -> GetProperty, Name=eventName
   CASE eventName OF

      'IGL_GRAPHIC PROPERTYSHEET': BEGIN

         IF event.type EQ 0 THEN BEGIN
            
            CASE StrUpCase(event.identifier) OF

               'POSITION': BEGIN

                  event.component -> GetProperty, Position=pos
                  event.id -> GetProperty, ID=group_leader
                  position = AdjustPosition(pos, Group_Leader=group_leader)
                  event.component -> SetProperty, Position=position

                  ;; Refresh the graphic hierarchy
                  IGL_RefreshDraw, event.component, /Buffered_Output
                  
               END

               ELSE: BEGIN

                  component = event.component
                  identifier = event.identifier
                  event.id -> GetProperty, Value=value, Component=component, Property_Value=identifier
                  event.component -> SetPropertyByIdentifier, identifier, value

                  ;; Refresh the graphic hierarchy
                  IF OBJ_VALID(event.component) THEN IGL_RefreshDraw, event.component, /Buffered_Output

               END

            ENDCASE

         ENDIF ; of BUTTON DOWN EVENT

      END                       ; of IGL_GRAPHIC PROPERYSHEET events

        ; If you can't handle the event here. Pass it along to superclass EventHandler
      ELSE: self -> CatDataAtom::EventHandler, event

   ENDCASE

   ;; Report completion
   IF Obj_Valid(self) THEN self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::GETPROPERTY
;
; PURPOSE:
;
;       This method is used to get the object's properties.
;
; SYNTAX:
;
;       self -> GetProperty
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     POSITION:            The current position of the graphic.
;
;     VISIBLE:             A flag indicating if the object is visible.
;
;     _REF_EXTRA:          Any keywords appropriate for the superclass GetProperty method.
;-
;*****************************************************************************************************
PRO IGL_Graphic::GetProperty, POSITION=position, $
                              VISIBLE=visible, $
                              DELETE=delete, $
                              _REF_EXTRA=extraKeywords

   @cat_pro_error_handler

   IF (obj_valid(self._coords)) THEN self._coords -> GetProperty, POSITION=position
   IF (arg_present(visible)) THEN visible = self.visible
   IF (arg_Present(delete)) THEN delete = 0 ; Dummy value for REGISTERPROPERTY functionality.

   ;; Get the CATDATAATOM properties
   IF (N_ELEMENTS (extraKeywords) GT 0) THEN self -> CATDATAATOM::GetProperty, _EXTRA=extraKeywords

   ;; Report completion
   self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::MOVE
;
; PURPOSE:
;
;       This method moves the graphic object in the current window. It
;       will also update the position of all the CATDATAATOM
;       children found in the graphic.
;
; SYNTAX:
;
;       self -> Move, x, y
;
; ARGUMENTS:
;
;       X:          The number of pixels to move in the X direction.
;
;       Y:          The number of pixels to move in the Y direction.
;
; KEYWORDS:
;
;       NODRAW:     If this keyword is set, only the coordinates are updated. No drawing occurs.
;
;       PIXMAP:     Set this keyword to a pixmap that can be used to erase the previous
;                   contents of the window.
;-
;*****************************************************************************************************
PRO IGL_Graphic::Move, x, y, PIXMAP=pixmap, NODRAW=noDraw
  
   @cat_pro_error_handler

   ;; Move the graphic itself
   ;; Convert the device pixels into normal coordinates.
   self._coords -> GetProperty, position=pos
   c = Convert_Coord(x,y,/Device,/To_Normal)

   ;; Calculate new position values
   xmin = pos[0]+c[0,0]
   xmax = pos[2]+c[0,0]
   ymin = pos[1]+c[1,0]
   ymax = pos[3]+c[1,0]

   ;; Make sure that we have a valid normalized position array
   IF (xmin LT 0) OR (ymin LT 0) OR (xmax GT 1) OR (ymax GT 1) THEN RETURN
   IF (xmin GE xmax) THEN xmin = xmax-0.001
   IF (xmax LE xmin) THEN xmax = xmin+0.001
   IF (ymin GE ymax) THEN ymin = ymax-0.001
   IF (ymax LE ymin) THEN ymax = ymin+0.001

   ;; Update the coordinate system of the graphic and all the children
   position = [xmin,ymin,xmax,ymax]
   self -> SetProperty, position=position

   ;; Do you need to draw?
   IF ~Keyword_Set(nodraw) THEN BEGIN
      IF Obj_Isa_Valid(pixmap, 'PIXMAPWIDGET') THEN BEGIN
         self -> CopyParameters, pixmap, Destination=d, Extent=e
         pixmap -> Copy, Destination=d, Extent=e, Origin=d
         self -> Draw
      ENDIF ELSE BEGIN
         CatRefreshDraw, self, Stop_At='DRAWWIDGET', /NoErase
      ENDELSE
   ENDIF
   
   ;; Report completion
   self -> Report, /Completed
   
END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::PAN
;
; PURPOSE:
;
;       This method performs a pan of the graphic object. The
;       pan will translate the data ranges of the
;       IGL_BaseRangeObject (typically plots and axis) and IGL_Image
;       contained in the graphic  by calling their own Pan method.
;
; SYNTAX:
;
;       self -> Pan, x, y
;
; ARGUMENTS:
;
;       X:          The number of pixels to pan in X direction.
;
;       Y:          The number of pixels to pan in Y direction.
;
; KEYWORDS:
;
;       NODRAW:     If this keyword is set, only the coordinates are updated. No drawing occurs.
;
;       PIXMAP:     Set this keyword to a pixmap that can be used to erase the previous
;                   contents of the window.
;
;-
;*****************************************************************************************************
PRO IGL_Graphic::Pan, x, y, PIXMAP=pixmap, NODRAW=noDraw

  @cat_pro_error_handler
  
  ;; Call the Pan method of all the IGL_BaseRangeObject children
  children = self -> Get(/All,ISA=['IGL_BaseRangeObject','IGL_Image'],count=count)
  FOR i=0, count-1 DO children[i] -> Pan, x,  y, PIXMAP=pixmap, NODRAW=nodraw

  ;; Do you need to draw?
  IF ~Keyword_Set(nodraw) THEN BEGIN
     IF Obj_Isa_Valid(pixmap, 'PIXMAPWIDGET') THEN BEGIN
        self -> CopyParameters, pixmap, Destination=d, Extent=e
        pixmap -> Copy, Destination=d, Extent=e, Origin=d
        self -> Draw
     ENDIF ELSE BEGIN
        CatRefreshDraw, self, Stop_At='DRAWWIDGET', /NoErase
     ENDELSE
  ENDIF

  ;; Report completion
  self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::SELECT
;
; PURPOSE:
;
;       This method returns the object reference if the requested point is inside
;       the bounding box defined by the position of the graphic.
;
; SYNTAX:
;
;       object = self -> Select(x,y)
;
; ARGUMENTS:
;
;       X:   The X location of a point in device or window coordinates.
;
;       Y:   The Y location of a point in device or window coordinates.
;
; KEYWORDS:
;
;       SUCCESS:   Set to 1 if a selection is made. To 0 otherwise.
;-
;*****************************************************************************************************
FUNCTION IGL_Graphic::Select, x, y, SUCCESS=success

   @cat_func_error_handler

   ;; Set up return values.
   retval = Obj_New()
   success = 0

   ;; No selection is possible if the object is invisible.
   IF self.visible EQ 0 THEN RETURN, retval

   ;; Make sure we have a valid coordinate system
   IF (OBJ_ISA_VALID(self._coords,'CatCoord') EQ 0) THEN RETURN, retval

   ;; Convert the point from device to normalized coordinates.
   c = Convert_Coord(x, y, /Device, /To_Normal)
   xx = c[0,0]
   yy = c[1,0]

   ;; Get the current graphic position
   self._coords -> GetProperty, position=pos
   
   ; Are you inside?
   isInside = Inside(xx, yy, [pos[0],pos[0],pos[2],pos[2]], [pos[1],pos[3],pos[3],pos[1]])
   
   IF isInside THEN BEGIN

      retVal = self
      success = 1

   ENDIF

   self -> Report, /Completed
   
   RETURN, retval

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::SETPROPERTY
;
; PURPOSE:
;
;       This method is used to set the object's properties.
;
; SYNTAX:
;
;       self -> SetProperty
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     POSITION:     A 4-element vector indicating the position of the
;                   graphic in normalized coordinates.
;
;     VISIBLE:        A flag indicating if the object is visible.
;
;     DELETE:      Set this keyword to destroy the object.
;
;     _EXTRA:       Any keyword accepted by the SetProperty method of
;                   the CATDATAATOM superclass.
;-
;*****************************************************************************************************
PRO IGL_Graphic::SetProperty, POSITION=position, $
                              VISIBLE=visible, $
                              DELETE=delete, $
                              _EXTRA=extraKeywords

   @cat_pro_error_handler

   IF (n_elements(position) NE 0) THEN BEGIN

      IF OBJ_ISA_VALID(self._coords,'CatCoord') THEN self._coords -> SetProperty, POSITION=position
   
      ;; Update the coordinate system of all the children
      children = self -> Get(/all,count=count,ISA='CatDataAtom')
      FOR i=0, count-1 DO BEGIN

         children[i] -> GetProperty, COORD_OBJECT=coords
         IF OBJ_ISA_VALID(coords,'CatCoord') THEN coords -> SetProperty, POSITION=position
      
      ENDFOR

   ENDIF

   IF (n_elements(visible) NE 0) THEN self.visible = visible

   IF (keyword_set(delete)) THEN BEGIN
      self -> SetProperty, Visible=0
      IGL_RefreshDraw, self, /Buffered_Output
      Obj_Destroy, self._controlPanel
      self -> GetProperty, Parent=parents
      self -> SendMessage, 'OBJECT_DELETED', DATA=self
      FOR j=0,N_Elements(parents)-1 DO IF OBJ_VALID(parents[j]) THEN parents[j] -> Remove, self
      Obj_Destroy, self
      RETURN
   ENDIF

   ;; Set CATDATAATOM properties
   self -> CATDATAATOM::SetProperty, _EXTRA=extraKeywords

   ;; Report completion
   self -> Report, /Completed

END

;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::SETRANGES
;
; PURPOSE:
;
;       This method is used to set the xrange and yrange of all
;       the IGL_BASERANGEOBJECT objects contained in the graphics.
;       Objects with a static coordinate system do NOT have their ranges updated by this method.
;
; SYNTAX:
;
;       self -> SetRanges
;
; ARGUMENTS:
;
;       None.
;
; KEYWORDS:
;
;       XRANGE:    A 2-element vector indicating the range in the X
;                  direction.
;
;       YRANGE:    A 2-element vector indicating the range in the Y
;                  direction.
;
;-
;*****************************************************************************************************
PRO IGL_Graphic::SetRanges, XRANGE=xrange, YRANGE=yrange


  ;; Update the ranges of the children 
  children = self -> Get(/All,ISA='IGL_BASERANGEOBJECT',count=count)
     
  FOR i=0, count-1 DO BEGIN

     ;; Get the coordinate system of the object
     children[i] -> GetProperty, COORD_OBJECT=coords

     IF OBJ_ISA_VALID(coords,'CatCoord') THEN coords -> SetProperty, XRANGE=xrange, YRANGE=yrange
        
  ENDFOR

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::ZOOMIN
;
; PURPOSE:
;
;       This method performs a zoom in of the graphic object. The
;       zoom in will decrease the data ranges of the
;       IGL_BaseRangeObject contained in the graphic (typically plots
;       and axis) as well as the IGL_Image objects by calling their own ZoomIn method.
;
; SYNTAX:
;
;       self -> ZoomIn, x, y
;
; ARGUMENTS:
;
;       X:          The X pixel location of the cursor in the current window.
;
;       Y:          The Y pixel location of the cursor in the current window.
;
; KEYWORDS:
;
;       NODRAW:     If this keyword is set, only the coordinates are updated. No drawing occurs.
;
;       PIXMAP:     Set this keyword to a pixmap that can be used to erase the previous
;                   contents of the window.
;-
;*****************************************************************************************************
PRO IGL_Graphic::ZoomIn, x, y, PIXMAP=pixmap, NODRAW=nodraw

  @cat_pro_error_handler

  ;; Call the ZoomIn method of all the IGL_BaseRangeObject children
  children = self -> Get(/All,ISA=['IGL_BaseRangeObject','IGL_Image'],count=count)
  FOR i=0, count-1 DO children[i] -> ZoomIn, x,  y, PIXMAP=pixmap, NODRAW=nodraw

  ;; Report completion
  self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::ZOOMOUT
;
; PURPOSE:
;
;       This method performs a zoom out of the graphic object. The
;       zoom out will increase the data ranges of the
;       IGL_BaseRangeObject contained in the graphic (typically plots
;       and axis) as well as the IGL_Image objects by calling their own ZoomOut method.
;
; SYNTAX:
;
;       self -> ZoomOut, x, y
;
; ARGUMENTS:
;
;       X:          The X pixel location of the cursor in the current window.
;
;       Y:          The Y pixel location of the cursor in the current window.
;
; KEYWORDS:
;
;        ALLTHEWAY:     If this keyword is set, all the
;                      IGL_BaseRangeObject children contained in the
;                      graphic will have their data ranges set  to the largest possible ranges to
;                      display all the elements of the graphic.
;
;       NODRAW:     If this keyword is set, only the coordinates are updated. No drawing occurs.
;
;       PIXMAP:     Set this keyword to a pixmap that can be used to erase the previous
;                   contents of the window.
;
;-
;*****************************************************************************************************
PRO IGL_Graphic::ZoomOut, x, y, ALLTHEWAY=alltheway, PIXMAP=pixmap, NODRAW=nodraw

  @cat_pro_error_handler

  ;; Here we need to reset the zoom scale factor of all the zoomable objects 
  IF (keyword_set(alltheway)) THEN BEGIN

     ;; Take care of possible images
     images = self -> Get(/ALL,ISA='IGL_IMAGE',count=count)
     FOR i=0, count-1 DO images[i] -> ZoomOut, x, y, /ALLTHEWAY, PIXMAP=pixmap, NODRAW=nodraw

     ;; Now loop over all non-static plot and contour objects in the graphic and calculate
     ;; the x and y ranges which encompass all of them.
     objects = self -> Get(/all,ISA=['IGL_PLOT','IGL_CONTOUR'],/RECURSIVE_SEARCH,count=count)
     
     FOR i=0, count-1 DO BEGIN
        
        currentObject = objects[i]   
        
        currentObject -> GetProperty, XMIN=xmin, XMAX=xmax, YMIN=ymin, YMAX=ymax, XDATA=xdata, YDATA=ydata, STATIC=IsStatic

        IF IsStatic THEN CONTINUE ; Do not take static objects into account when calculating the ranges 

        IF (obj_isa(currentObject,'IGL_Plot')) THEN BEGIN

           currentObject -> GetProperty, polar=polar
           IF (polar) THEN BEGIN 
              rects = CV_COORD(from_polar=transpose([[ydata],[xdata]]),/to_rect)
              xdata = rects[0,*]
              ydata = rects[1,*]
           ENDIF

        ENDIF        
        
        IF (n_elements(xrange) EQ 0) THEN BEGIN

           IF (xmin GT xmax) THEN xrange = [max(xdata),min(xdata)] ELSE xrange = [min(xdata),max(xdata)]
           IF (ymin GT ymax) THEN yrange = [max(ydata),min(ydata)] ELSE yrange = [min(ydata),max(ydata)]
           
        ENDIF ELSE BEGIN
           
           IF (xrange[0] GT xrange[1]) THEN BEGIN
              xrange[0] = xrange[0] > max(xdata)
              xrange[1] = xrange[1] < min(xdata)
           ENDIF ELSE BEGIN
              xrange[0] = xrange[0] < min(xdata)
              xrange[1] = xrange[1] > max(xdata)
           ENDELSE

           IF (yrange[0] GT yrange[1]) THEN BEGIN
              yrange[0] = yrange[0] > max(ydata)
              yrange[1] = yrange[1] < min(ydata)
           ENDIF ELSE BEGIN
              yrange[0] = yrange[0] < min(ydata)
              yrange[1] = yrange[1] > max(ydata)
           ENDELSE

        ENDELSE
     
     ENDFOR
  
     ;; Now assign the ranges to all the IGL_BASERANGEOBJECT objects
     IF count GT 0 THEN self -> SetRanges, XRANGE=xrange, YRANGE=yrange
  
  ENDIF ELSE BEGIN

     ;; Here we perform a regular ZoomOut on all the children
     children = self -> Get(/All,ISA=['IGL_BaseRangeObject','IGL_Image'],count=count)
     FOR i=0, count-1 DO children[i] -> ZoomOut, x,  y, PIXMAP=pixmap, NODRAW=nodraw
     
  ENDELSE

  ;; Do you need to draw?
  IF ~Keyword_Set(nodraw) THEN BEGIN
     IF Obj_Isa_Valid(pixmap, 'PIXMAPWIDGET') THEN BEGIN
        self -> CopyParameters, pixmap, Destination=d, Extent=e
        pixmap -> Copy, Destination=d, Extent=e, Origin=d
        self -> Draw
     ENDIF ELSE BEGIN
        CatRefreshDraw, self, Stop_At='DRAWWIDGET', /NoErase
     ENDELSE
  ENDIF
  
  ;; Report completion
  self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::CLEANUP
;
; PURPOSE:
;
;       This is the IGL_Graphic object class destructor method.
;
; SYNTAX:
;
;       Called automatically when the object is destroyed.
;
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     None.
;-
;*****************************************************************************************************
PRO IGL_Graphic::CLEANUP

   @cat_pro_error_handler

   ;; Cleanup the superclass
   self -> CATDATAATOM::CLEANUP

   ;; Report completion
   self -> Report, /Completed

END


;*****************************************************************************************************
;+
; NAME:
;       IGL_Graphic::INIT
;
; PURPOSE:
;
;       This is the IGL_Graphic object class creator method.
;
; SYNTAX:
;
;       Called automatically when the object is created.
;
; ARGUMENTS:
;
;     None.
;
; KEYWORDS:
;
;     POSITION:     A 4-element vector indicating the position of the
;                   graphic in normalized coordinates. The default is !IGL_P.position.
; 
;     COORD_OBJECT:  A reference to a subclass CatCoord object which becomes
;                                         the coordinate system for this object. 
;                                         The position of the coordinate system is set to the POSITION array
;                                         passed as keyword.
;
;     _EXTRA:       Any keywords accepted by the CATDATAATOM::Init method.
;
;-
;*****************************************************************************************************
FUNCTION IGL_Graphic::INIT, POSITION=position, $
                            COORD_OBJECT=coord_object, $
                            _EXTRA=extraKeywords

   @cat_func_error_handler

   ;; Initialize the global system variables
   IGL_InitSysVars

   ;; Default keyword values
   IF (n_elements(position) EQ 0) THEN position = !IGL_P.position
   IF (total(position) EQ 0) THEN pos = [0.1,0.1,0.9,0.9] ELSE pos = position

   ;; Create the graphic coordinate system
   IF OBJ_ISA_VALID(coord_object,'CatCoord') THEN coord_object -> SetProperty, Xrange=[0,1], Yrange=[0,1], Position=pos $
   ELSE coord_object = obj_new('CatCoord',XRANGE=[0,1],YRANGE=[0,1],POSITION=pos)

   ;; Initialize the superclass
   ok = self -> CATDATAATOM::INIT(NAME='Graphic', $
                                  DESCRIPTION='Graphic visualization', $
                                  COORD_OBJECT=coord_object, $
                                  _EXTRA=extraKeywords)
   IF (NOT ok) THEN RETURN, 0

   self.visible = 1

   ; Set up editable properties
   self -> SetPropertyAttribute, 'name', sensitive=0
   self -> SetPropertyAttribute, 'description', sensitive=0
   self -> RegisterProperty, 'DELETE', /boolean, name='Delete Object'
   self -> RegisterProperty, 'POSITION', 0, userdef='Adjust position', name='Graphic Position'

   ;; Report completion
   self -> Report, /Completed

   RETURN, 1

END


;*****************************************************************************************************
;
; NAME:
;       IGL_GRAPHIC CLASS DEFINITION
;
; PURPOSE:
;
;       This is the IGL_Graphic object's structure definition code.
;
;*****************************************************************************************************
PRO IGL_Graphic__Define, class

  COMPILE_OPT idl2, HIDDEN

   class = {IGL_Graphic, $
            INHERITS CATDATAATOM, $ ; This is a CATDATAATOM object
            visible:0B $ 
           }

   struct_hide, class

END
